{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# A [Paul Graham classic](http://www.paulgraham.com/icad.html), the accumulator function.\n",
    "\n",
    "> As an illustration of what I mean about the relative power of programming languages, consider the following problem. We want to write a function that generates accumulators-- a function that takes a number n, and returns a function that takes another number i and returns n incremented by i.\n",
    "\n",
    "> (That's incremented by, not plus. An accumulator has to accumulate.)\n",
    "\n",
    "> In Common Lisp this would be\n",
    "\n",
    "> `(defun foo (n)\n",
    "  (lambda (i) (incf n i)))`\n",
    "\n",
    "> ...\n",
    "\n",
    "> If you try to translate the Lisp/Perl/Smalltalk/Javascript code into Python you run into some limitations. Because Python doesn't fully support lexical variables, you have to create a data structure to hold the value of n. And although Python does have a function data type, there is no literal representation for one (unless the body is only a single expression) so you need to create a named function to return. This is what you end up with:\n",
    "\n",
    "> `def foo(n):\n",
    "  s = [n]\n",
    "  def bar(i):\n",
    "    s[0] += i\n",
    "    return s[0] \n",
    "  return bar`\n",
    "\n",
    ">Python users might legitimately ask why they can't just write\n",
    "\n",
    "> `def foo(n):\n",
    "  return lambda i: return n += i`\n",
    "\n",
    "> or even\n",
    "\n",
    "> `def foo(n):\n",
    "  lambda i: n += i`\n",
    "\n",
    "> and my guess is that they probably will, one day. (But if they don't want to wait for Python to evolve the rest of the way into Lisp, they could always just...) \n",
    "\n",
    "There are [other solutions](https://en.wikipedia.org/wiki/Function_object#In_Python), using function attributes or instances with a `__call__` method, but none are substantially more elegant.  The challenge predates Python 3, which introduced the `nonlocal` keyword, making this the presumably preferred solution:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": "3"
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def foo(n):\n",
    "    def inc(x):\n",
    "        nonlocal n\n",
    "        n += x\n",
    "        return n\n",
    "    return inc\n",
    "\n",
    "acc = foo(0)\n",
    "acc(1)\n",
    "acc(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "There was also yet another alternative as of Python 2.6: using a generator as a coroutine."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": "3"
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def foo(n):\n",
    "    while True:\n",
    "        n += yield n\n",
    "\n",
    "acc = foo(0)\n",
    "next(acc)\n",
    "acc.send(1)\n",
    "acc.send(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To satisfy the challenge, that would need to be wrapped with a decorator.  The triple `partial` expression below may seem a little obtuse, but it's not as bad as it looks.  Just unwind it one step at a time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": "functools.partial(<class 'functools.partial'>, <function coroutine at 0x10bf970e0>)"
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from functools import partial\n",
    "\n",
    "@partial(partial, partial)\n",
    "def coroutine(func, *args, **kwargs):\n",
    "    gen = func(*args, **kwargs)\n",
    "    next(gen)\n",
    "    return gen.send\n",
    "\n",
    "coroutine"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": "functools.partial(<function coroutine at 0x10bf970e0>, <function foo at 0x10bf7eb90>)"
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "@coroutine\n",
    "def foo(n):\n",
    "    while True:\n",
    "        n += yield n\n",
    "\n",
    "foo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": "<function generator.send>"
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "acc = foo(0)\n",
    "acc"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": "3"
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "acc(1)\n",
    "acc(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "But what's the most Pythonic solution?  This author would argue... don't.  In my experience, I have never really needed `global` or `nonlocal` in production code.  Typically it's because the objects in question are *mutable*, so it's not necessary to rebind a name in a different scope to a new object.\n",
    "\n",
    "A typical tell of these kinds of code challenges are that they focus on the interface or implementation exclusively, never both in context.  Python numbers are immutable, and have syntactic support for incrementing, so there's nothing more readable about `acc(...)` instead of `n += ...`.\n",
    "\n",
    "Futhermore, the accumulator object is intended to be used repeatedly, such as in a loop.  In a language with such strong iteration support as Python, it's extremely likely that accumulation will occur in a iterative loop.  Indeed, the _real_ accumulator has since been added to the standard library."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": "[0, 1, 3, 6, 10, 15, 21, 28, 36, 45]"
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import itertools\n",
    "\n",
    "list(itertools.accumulate(range(10)))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "env": {},
   "interrupt_mode": "signal",
   "language": "python",
   "metadata": {},
   "name": "python3"
  },
  "nikola": {
   "category": "style",
   "date": "2018-05-28",
   "description": "",
   "link": "",
   "slug": "accumulator",
   "tags": "",
   "title": "Accumulator",
   "type": "text"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}